﻿/******************************************************************************
 *
 * @copyright:          Copyright 2011 UniSky Ltd.
 * @file:
 * @author:              kenping.liu
 * @creation:
 * @description:
 *
 * @modifications
 * date         user                description
 * 2015-03-02	Degang.Wu			+ get_monotonic()
 *									+ get_mono_seconds()
 * @more-details
 *
 *****************************************************************************/

#include "u/u_util.h"
#include "u/u_logger.h"
#include "u/u_io.h"

U_NAMESPACE_BEGIN(u)

UINT Util::get_tick_count()
{
#if defined(WINDOWS)
    return (UINT)GetTickCount();
#else
    struct timeval current;
    gettimeofday(&current, NULL);
    return (UINT)(((UINT)current.tv_sec)*1000 + current.tv_usec/1000);
#endif
}

void Util::get_current_time(u::util::U_TIME* curtime)
{
#if defined(WINDOWS)
    SYSTEMTIME systm = {0};
    ::GetLocalTime(&systm);
    curtime->year   = systm.wYear;
    curtime->month  = systm.wMonth;
    curtime->day    = systm.wDay;
    curtime->hour   = systm.wHour;
    curtime->minute = systm.wMinute;
    curtime->second = systm.wSecond;
    curtime->milliseconds = systm.wMilliseconds;
#else
    time_t     long_time;
    struct tm  occurs = {0};
    time(&long_time);
    occurs = *localtime((time_t *)&long_time);
    curtime->year   = occurs.tm_year + 1900;
    curtime->month  = occurs.tm_mon+1;
    curtime->day    = occurs.tm_mday;
    curtime->hour   = occurs.tm_hour;
    curtime->minute = occurs.tm_min;
    curtime->second = occurs.tm_sec;
    curtime->milliseconds = 0;
    curtime->weekday = get_week_day(curtime->year, curtime->month, curtime->day);
#endif
}


/*
 计算公式） 算法如下：
基姆拉尔森计算公式
W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
在公式中d表示日期中的日数，m表示月份数，y表示年数。
注意：在公式中有个与其他公式不同的地方：
把一月和二月看成是上一年的十三月和十四月，例：如果是2004-1-10则换算成：2003-13-10来代入公式计算。
以公元元年为参考，公元元年1月1日为星期一程序如下： 利用基姆拉尔森计算日期公式 w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)
*/
UINT Util::get_week_day(int y, int m, int d) {
	int w; //代表星期几

	if (m == 1 || m == 2)
	{
		m += 12;
		y--;
	}

	w = (d + 1 + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;

	return w;
}

void Util::seconds2time(u::util::U_TIME* utm, UINT seconds)
{
    ZeroMemory(utm, sizeof(u::util::U_TIME));
#if defined(WINDOWS)
    //localtime_s(&occurs, (time_t *)&seconds);
    SYSTEMTIME systm = {0};
    FILETIME ft;
    LONGLONG ll = Int32x32To64(seconds, 10000000) + 116444736000000000;
    ft.dwLowDateTime = (DWORD) ll;
    ft.dwHighDateTime = (ll >> 32);
    FileTimeToLocalFileTime(&ft, &ft);
    FileTimeToSystemTime(&ft, &systm);
    
    utm->year   = systm.wYear;
    utm->month  = systm.wMonth;
    utm->day    = systm.wDay;
    utm->hour   = systm.wHour;
    utm->minute = systm.wMinute;
    utm->second = systm.wSecond;
    utm->milliseconds = systm.wMilliseconds;
#else
    struct tm  occurs = {0};
    time_t _seconds = seconds;
    occurs = *localtime((time_t *)&_seconds);
    utm->year   = occurs.tm_year + 1900;
    utm->month  = occurs.tm_mon+1;
    utm->day    = occurs.tm_mday;
    utm->hour   = occurs.tm_hour;
    utm->minute = occurs.tm_min;
    utm->second = occurs.tm_sec;
    utm->milliseconds = 0;
    utm->weekday = get_week_day(utm->year, utm->month, utm->day);
#endif
}

UINT Util::seconds(u::util::U_TIME* utm)
{
    if ( NULL==utm )
    {
        time_t long_time;
        time(&long_time);
        return (UINT)long_time;
    }
    else
    {
        struct tm curtm = {0};
        curtm.tm_year = utm->year - 1900;
        curtm.tm_mon  = utm->month - 1;
        curtm.tm_mday = utm->day;
        curtm.tm_hour = utm->hour;
        curtm.tm_min  = utm->minute;
        curtm.tm_sec  = utm->second;
        return (UINT)mktime(&curtm);
    }
}

char* Util::module_folder()
{
    static char tmp[MAX_PATH] = {0};
    if ( strlen(tmp)<1 )
    {
#if defined(WINDOWS)
        GetModuleFileName(NULL, tmp, MAX_PATH);
#else
        char szTmp[32];
        u_sprintf(szTmp, "/proc/%d/exe", getpid());
        int bytes = u_min(readlink(szTmp, tmp, MAX_PATH), MAX_PATH - 1);
        if(bytes >= 0)
        {
            tmp[bytes] = '\0';
        }
#endif
        size_t len = strlen(tmp);
        for ( size_t i=len; i>0; i-- )
        {
            if ( tmp[i]=='\\' || tmp[i]=='/' )
            {
                ZeroMemory(&tmp[i], MAX_PATH-i);
                break;
            }
        }
    }
    return tmp;
}

char* Util::module_name()
{
    static char tmp[MAX_PATH] = {0};
    if ( strlen(tmp)<1 )
    {
#if defined(WINDOWS)
        GetModuleFileName(NULL, tmp, MAX_PATH);
#else
        char szTmp[32];
        u_sprintf(szTmp, "/proc/%d/exe", getpid());
        int bytes = u_min(readlink(szTmp, tmp, MAX_PATH), MAX_PATH - 1);
        if(bytes >= 0)
        {
            tmp[bytes] = '\0';
        }
#endif
        io::PATH path;
        io::File::split(&path, tmp);
        snprintf(tmp, sizeof(tmp), "%s", path.file);
    }
    return tmp;
}

bool Util::shell_exec(const char* cmd, const char* param, const char* dir, int wait)
{
//    u::Log::trace("shell_exec[cmd='%s', param='%s']", cmd, param);

#if defined(WINDOWS)
    SHELLEXECUTEINFO ShExecInfo = {0};
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = NULL;   // ""
    ShExecInfo.lpFile = cmd;		
    ShExecInfo.lpParameters = param;	
    ShExecInfo.lpDirectory = dir;
    ShExecInfo.nShow = SW_HIDE;
    ShExecInfo.hInstApp = NULL;	
    if ( ShellExecuteEx(&ShExecInfo) )
    {
        if ( wait )
        {
            WaitForSingleObject(ShExecInfo.hProcess, wait<=0? INFINITE : (DWORD)wait);
        }
        return true;
    }
    else
    {
        u::Log::info("shell_exec[cmd='%s', param='%s'] ShellExecuteEx failed: %s", cmd, param, u::get_error_msg());
    }
    return false;
#else
//    pid_t pid = fork();
//    if ( pid==0 )
//    {
//        char *fargs[] = {(char*)ffmpeg, "-i",
//            task.ts,
//            "-y", "-vcodec", "copy", "-acodec", "copy",
//            task.mp4,
//            (char*)0 };
//        execv(fargs[0], fargs);
//    }

    char cmdline[1024] = {0};
    char chdir[1024] = {0};
    if ( NULL!=dir && strlen(dir)>0 )
    {
        u_sprintf(chdir, "cd \"%s\";", dir);
    }
    if ( NULL!=param && strlen(param)>0 )
    {
        u_sprintf(cmdline, "%s%s %s", chdir, cmd, param);
    }
    else
    {
        u_sprintf(cmdline, "%s%s", chdir, cmd);
    }
    u::Log::trace("system cmdline='%s'", cmdline);
    int ret = system(cmdline);
    if (-1 == ret) {
    	perror("system");
    }
    return true;
#endif
}

std::string Util::shell_exec_ex(const char* cmd, const char* param, const char* dir)
{
    std::string result;

    char cmdline[MAX_PATH] = {0};
    char chdir[MAX_PATH]   = {0};

    if ( NULL!=dir && strlen(dir)>0 )
    {
        u_sprintf(chdir, "cd \"%s\";", dir);
    }
    if ( NULL!=param && strlen(param)>0 )
    {
        u_sprintf(cmdline, "%s%s %s", chdir, cmd, param);
    }
    else
    {
        u_sprintf(cmdline, "%s%s", chdir, cmd);
    }

//    u::Log::trace("shell_exec_ex cmdline='%s'", cmdline);

    FILE *pipe;
    char buf[1024] = {0};
    if ( (pipe = popen(cmdline, "r")) != NULL )
    {
        while ( !feof(pipe) && !ferror(pipe) )
        {
            size_t n = fread(buf, 1, 1024, pipe);
            result.append(buf, n);
        }
        pclose(pipe);
    }

    return result;
}

int64_t Util::get_monotonic()
{
    struct timespec tv;

    clock_gettime(CLOCK_MONOTONIC, &tv);
    return (int64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
}

int64_t Util::get_mono_seconds()
{
    struct timespec tv;

    clock_gettime(CLOCK_MONOTONIC, &tv);
    return (int64_t)tv.tv_sec;
}

int64_t Util::get_timestamp()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}
		

U_NAMESPACE_END(u)
